// 在文档内容加载完成后执行
document.addEventListener('DOMContentLoaded', () => {
    // 获取类名为'grid'的元素
    const grid = document.querySelector('.grid');
    // 棋盘大小为4x4
    const size = 4;
    // 初始化棋盘数组
    let board = [];
    // 初始化当前分数为0
    let currentScore = 0;
    // 获取id为'current-score'的元素，用于显示当前分数
    const currentScoreElem = document.getElementById('current-score');

    // 从本地存储获取最高分，如果找不到，则将其设置为0
    let highScore = localStorage.getItem('2048-highScore') || 0;
    // 获取页面中用于显示高分的元素
    const highScoreElem = document.getElementById('high-score');
    // 将高分记录显示在页面上
    highScoreElem.textContent = highScore;

    // 获取名为'game-over'的元素
    const gameOverElem = document.getElementById('game-over');

    // 函数更新分数
    function updateScore(value) {
        currentScore += value;
        currentScoreElem.textContent = currentScore;
        if (currentScore > highScore) {
            highScore = currentScore;
            highScoreElem.textContent = highScore;
            localStorage.setItem('2048-highScore', highScore);
        }
    }

    // 重新开始游戏的功能
    function restartGame() {
        currentScore = 0;
        currentScoreElem.textContent = '0';
        gameOverElem.style.display = 'none';
        initializeGame();
    }

    // 初始化游戏的函数
    function initializeGame() {
        // 所有数值为0，初始化棋盘数组
        board = [...Array(size)].map(e => Array(size).fill(0));
        placeRandom();
        placeRandom();
        renderBoard();
    }

    // 在UI上渲染游戏板的功能
    // 渲染游戏板面
    function renderBoard() {
        for (let i = 0; i < size; i++) { 
            for (let j = 0; j < size; j++) {
                // 获取对应位置的单元格元素
                const cell = document.querySelector(`[data-row="${i}"][data-col="${j}"]`);
                // 保存先前数值
                const prevValue = cell.dataset.value;
                // 获取当前数值
                const currentValue = board[i][j];
                // 如果当前数值不为0
                if (currentValue !== 0) {
                    // 更新单元格数据值和显示文本
                    cell.dataset.value = currentValue;
                    cell.textContent = currentValue;
                    // 动画处理
                    if (currentValue !== parseInt(prevValue) && !cell.classList.contains('new-tile')) {
                        cell.classList.add('merged-tile');
                    }
                } else {
                    // 清空单元格文本并移除数据值，合并标记以及新块标记
                    cell.textContent = '';
                    delete cell.dataset.value;
                    cell.classList.remove('merged-tile', 'new-tile');
                }
            }
        }
    }
        // 清理动画类
    // 在函数级别添加注释
    // 该函数使用setTimeout延迟执行，清除所有游戏格子的特定类名
    // 清除类名包括'merged-tile'和'new-tile'
    // 延迟时间为300毫秒
    function clearTiles() {
        setTimeout(() => {
            const cells = document.querySelectorAll('.grid-cell');
            cells.forEach(cell => {
                cell.classList.remove('merged-tile', 'new-tile');
            });
        }, 300);
    }

    // 函数放置一个随机的贴图在棋盘上
    function placeRandom() {
        // 在游戏面板中随机放置数字方块
        const available = [];
        for (let i = 0; i < size; i++) {
            for (let j = 0; j < size; j++) {
                // 检查每个位置是否为空，如果是则加入可用位置列表
                if (board[i][j] === 0) {
                    available.push({ x: i, y: j });
                }
            }
        }
    
        if (available.length > 0) {
            // 从可用位置列表中随机选择一个位置
            const randomCell = available[Math.floor(Math.random() * available.length)];
            // 根据概率随机生成 2 或 4 放置在选定位置
            board[randomCell.x][randomCell.y] = Math.random() < 0.9 ? 2 : 4;
            // 获取选定位置的 DOM 元素，添加新方块的动画效果类
            const cell = document.querySelector(`[data-row="${randomCell.x}"][data-col="${randomCell.y}"]`);
            cell.classList.add('new-tile'); // 新贴图的动画
        }
    }

    // 基于箭头键输入移动贴图的功能
    function move(direction) {
        // 移动棋盘上的数字方块
        // 如果移动导致数字方块的位置发生变化，则生成新的数字方块并更新显示，同时检查游戏是否结束
        let hasChanged = false;
        if (direction === 'ArrowUp' || direction === 'ArrowDown') {
            // 对每一列进行处理
            for (let j = 0; j < size; j++) {
                // 提取出当前列的数字方块
                const column = [...Array(size)].map((_, i) => board[i][j]);
                // 根据移动方向对当前列进行变换
                const newColumn = transform(column, direction === 'ArrowUp');
                // 更新棋盘状态并标记是否发生变化
                for (let i = 0; i < size; i++) {
                    if (board[i][j] !== newColumn[i]) {
                        hasChanged = true;
                        board[i][j] = newColumn[i];
                    }
                }
            }
        } else if (direction === 'ArrowLeft' || direction === 'ArrowRight') {
            // 对每一行进行处理
            for (let i = 0; i < size; i++) {
                // 提取出当前行的数字方块
                const row = board[i];
                // 根据移动方向对当前行进行变换
                const newRow = transform(row, direction === 'ArrowLeft');
                // 更新棋盘状态并标记是否发生变化
                if (row.join(',') !== newRow.join(',')) {
                    hasChanged = true;
                    board[i] = newRow;
                }
            }
        }
        // 如果棋盘状态发生变化，则生成新的数字方块，更新显示，并检查游戏是否结束
        if (hasChanged) {
            placeRandom();
            renderBoard();
            checkGameOver();
        }
    }

    // 基于移动方向变换线(行或列)的函数
    function transform(line, moveTowardsStart) {
        // 定义一个用于处理一行方块的函数，根据移动方向对该行进行变换
        // 参数 line: 要处理的一行方块数组
        // 参数 moveTowardsStart: 指示移动方向的布尔值，true 表示向数组起始位置移动，false 表示向末尾位置移动
    
        let newLine = line.filter(cell => cell !== 0); // 过滤掉数组中的0元素，得到新的非零元素数组
        if (!moveTowardsStart) {
            newLine.reverse(); // 如果移动方向向末尾位置，则反转数组顺序
        }
        for (let i = 0; i < newLine.length - 1; i++) {
            if (newLine[i] === newLine[i + 1]) {
                newLine[i] *= 2; // 如果相邻元素相等，则将前一个元素翻倍
                updateScore(newLine[i]); // 当贴图合并时更新分数
                newLine.splice(i + 1, 1); // 删除合并的后一个元素
            }
        }
        while (newLine.length < size) {
            newLine.push(0); // 将数组补充至指定长度，用0填充
        }
        if (!moveTowardsStart) {
            newLine.reverse(); // 如果之前反转过数组，则再次反转恢复原顺序
        }
        return newLine; // 返回变换后的一行方块数组
    }

    // 检查游戏是否结束的功能
    function checkGameOver() {
        for (let i = 0; i < size; i++) {
            for (let j = 0; j < size; j++) {
                if (board[i][j] === 0) {
                    return; // 还有一个空格子，所以游戏还没结束
                }
                if (j < size - 1 && board[i][j] === board[i][j + 1]) {
                    return; // 有水平相邻的相等单元格，所以移动是可能的
                }
                if (i < size - 1 && board[i][j] === board[i + 1][j]) {
                    return; // 有垂直相邻的相等单元格，所以移动是可能的
                }
            }
        }

        // 如果我们到了这里，任何行动都不可能了
        gameOverElem.style.display = 'flex';
    }

    // 事件监听器
    // 添加键盘事件监听器，当按键按下时触发回调函数
    document.addEventListener('keydown', event => {
        // 如果按下的键是上下左右箭头键之一
        if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) {
            // 调用move函数，传入按下的键作为参数
            move(event.key);
        }
    });
    
    // 添加重新开始按钮的点击事件监听器，点击时触发restartGame函数
    document.getElementById('restart-btn').addEventListener('click', restartGame);
    
    // 调用initializeGame函数，初始化游戏
    initializeGame();

});